package cn.coufran.springboot.starter.http;

import cn.coufran.springboot.starter.http.content.*;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * HTTP请求
 * @author Coufran
 * @version 2.0.0
 * @since 1.0.0
 */
public class HttpRequest {
    /** HTTP方法 */
    private HttpMethod method;
    /** URL路径 */
    private String url;
    /** HTTP请求参数 */
    private Map<String, String> params = new HashMap<>();
    /** HTTP请求头 */
    private Map<String, String> headers = new HashMap<>();
    /** HTTP请求体内容 */
    private List<HttpRequestBodyContent> contents = new ArrayList<>();
    /** HTTP请求内容类型 */
    private ContentType contentType = ContentType.of(MediaType.APPLICATION__JSON);

    /**
     * 构造HTTP请求
     * @param method HTTP方法
     * @param url URL路径
     */
    private HttpRequest(HttpMethod method, String url) {
        this.method = method;
        this.url = url;
    }

    /**
     * 构造HTTP GET请求
     * @param url URL路径
     * @return HTTP请求
     */
    public static HttpRequest get(String url) {
        return new HttpRequest(HttpMethod.GET, url);
    }

    /**
     * 构造HTTP POST请求
     * @param url URL路径
     * @return HTTP请求
     */
    public static HttpRequest post(String url) {
        return new HttpRequest(HttpMethod.POST, url);
    }

    /**
     * 获取URL路径
     * @return URL路径
     */
    public String url() {
        return url;
    }

    /**
     * 获取HTTP方法
     * @return HTTP方法
     */
    public HttpMethod method() {
        return method;
    }

    /**
     * 获取HTTP参数
     * @return HTTP参数
     */
    public Map<String, String> params() {
        return params;
    }

    /**
     * 设置HTTP参数（增量覆盖）
     * @param params HTTP参数
     * @return HTTP请求
     */
    public HttpRequest params(Map<String, String> params) {
        this.params.putAll(params);
        return this;
    }

    /**
     * 设置HTTP参数
     * @param key HTTP参数键
     * @param value HTTP参数值
     * @return HTTP请求
     */
    public HttpRequest param(String key, String value) {
        params.put(key, value);
        return this;
    }

    /**
     * 获取HTTP请求头
     * @return HTTP请求头
     */
    public Map<String, String> headers() {
        return headers;
    }

    /**
     * 设置HTTP请求头（增量覆盖）
     * @param headers HTTP请求头
     * @return HTTP请求
     */
    public HttpRequest headers(Map<String, String> headers) {
        this.headers.putAll(headers);
        return this;
    }

    /**
     * 设置HTTP请求头
     * @param name HTTP请求头键
     * @param value HTTP请求头值
     * @return HTTP请求
     */
    public HttpRequest header(String name, String value) {
        headers.put(name, value);
        return this;
    }

    /**
     * 获取HTTP请求体内容类型
     * @return HTTP请求体内容类型
     */
    public ContentType contentType() {
        return contentType;
    }

    /**
     * 设置HTTP请求体内容类型
     * @param contentType HTTP请求体内容类型
     * @return HTTP请求
     */
    public HttpRequest contentType(String contentType) {
        this.contentType(ContentType.of(contentType));
        return this;
    }

    /**
     * 设置HTTP请求体内容类型
     * @param contentType HTTP请求体内容类型
     * @return HTTP请求
     */
    public HttpRequest contentType(ContentType contentType) {
        this.contentType = contentType;
        return this;
    }

    /**
     * 获取HTTP请求体内容
     * @return HTTP请求体内容
     */
    public List<HttpRequestBodyContent> contents() {
        return contents;
    }

    /**
     * 设置HTTP请求体
     * @param contents HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest contents(List<HttpRequestBodyContent> contents) {
        if (contents == null) {
            contents = new ArrayList<>();
        }
        this.contents = contents;
        return this;
    }

    /**
     * 设置HTTP请求体
     * @param content HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(HttpRequestBodyContent content) {
        this.contents.add(content);
        return this;
    }

    /**
     * 设置HTTP请求体
     * @param name 该部分请求体的名称
     * @param content 该HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(String name, String content) {
        return this.content(new TextContent(name, content));
    }

    /**
     * 设置HTTP请求体
     * @param content HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(String content) {
        return this.content(new TextContent(content));
    }

    /**
     * 设置HTTP请求体
     * @param name 该部分请求体的名称
     * @param content 该HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(String name, byte[] content) {
        return this.content(new BinaryContent(name, content));
    }

    /**
     * 设置HTTP请求体
     * @param content HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(byte[] content) {
        return this.content(new BinaryContent(content));
    }

    /**
     * 设置HTTP请求体
     * @param name 该部分请求体的名称
     * @param content 该HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(String name, File content) {
        return this.content(new FileContent(name, content));
    }

    /**
     * 设置HTTP请求体
     * @param content HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(File content) {
        return this.content(new FileContent(content));
    }

    /**
     * 设置HTTP请求体
     * @param name 该部分请求体的名称
     * @param content 该HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(String name, InputStream content) {
        return this.content(new StreamContent(name, content));
    }

    /**
     * 设置HTTP请求体
     * @param content HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(InputStream content) {
        return this.content(new StreamContent(content));
    }

    /**
     * 设置HTTP请求体
     * @param name 该部分请求体的名称
     * @param content 该HTTP请求体内容
     * @return HTTP请求
     */
    public HttpRequest content(String name, Object content) {
        return this.content(name, JSON.toJSONString(content, JSONWriter.Feature.WriteEnumsUsingName));
    }

    /**
     * 设置HTTP请求体，默认APPLICATION_JSON
     * @param content HTTP请求体内容，会转换为JSON
     * @return HTTP请求
     */
    public HttpRequest content(Object content) {
        return this.content(JSON.toJSONString(content, JSONWriter.Feature.WriteEnumsUsingName));
    }

    /**
     * 使用默认HTTP客户端执行HTTP请求
     * @return HTTP响应
     */
    public HttpResponse execute() {
        return this.execute(HttpClient.INSTANCE_DEFAULT);
    }

    /**
     * 使用指定的HTTP客户端执行HTTP请求
     * @param client HTTP客户端
     * @return HTTP响应
     */
    public HttpResponse execute(HttpClient client) {
        return client.execute(this);
    }

    /**
     * 转换为字符串
     * @return 字符串
     */
    @Override
    public String toString() {
        return "HttpRequest{" +
                "method=" + method +
                ", url='" + url + '\'' +
                ", headers=" + headers +
                ", params=" + params +
                ", contents='" + contents + '\'' +
                ", contentType=" + contentType +
                '}';
    }
}
